import pandas as pd
import numpy as np
from matplotlib import cm
import matplotlib.pyplot as plt
import math

data = pd.read_excel('Test_Train_Set.xls')
test_Desired=data.iloc[:,[0]].values
test_Input1=data.iloc[:,[1]].values
test_Input2=data.iloc[:,[2]].values
train_Desired=data.iloc[:,[3]].values
train_Input1=data.iloc[:,[4]].values
train_Input2=data.iloc[:,[5]].values


#定义函数
def lgstc(x):
    return 1/(1+math.exp(-x))
def Del_w0(Input1,Input2,Desired,w0,w1,w2):
    sumDel = 0
    for i in range(len(Input1)):
        lc_p = lgstc(w0+w1*Input1[i]+w2*Input2[i])
        sumDel += Desired[i] -lc_p
    return sumDel
def Del_w1(Input1,Input2,Desired,w0,w1,w2):
    sumDel = 0
    for i in range(len(Input1)):
        lc_p = lgstc(w0+w1*Input1[i]+w2*Input2[i])
        sumDel += Input1[i]* (Desired[i] -lc_p)
    return sumDel
def Del_w2(Input1,Input2,Desired,w0,w1,w2):
    sumDel = 0
    for i in range(len(Input1)):
        lc_p = lgstc(w0+w1*Input1[i]+w2*Input2[i])
        sumDel += Input2[i]* (Desired[i] -lc_p)
    return sumDel

def Loss(Input1,Input2,Desired,w0,w1,w2):
    loss = 0
    for i in range(len(Input1)):
        lc_p = lgstc(w0+w1*Input1[i]+w2*Input2[i])
        loss += Desired[i]*math.log(lc_p)+(1-Desired[i])*math.log(1-lc_p)
    return loss


def GDM_LC(Input1,Input2,Desired,w0=0,w1=0,w2=0,Alpha = 0.1,err = 1e-9):
    w0_list = []
    w1_list = []
    w2_list = []
    loss_list = []
    IterTime = 0

    while 1:
        w0,w1,w2=\
        w0+ Alpha*Del_w0(Input1,Input2,Desired,w0,w1,w2), \
        w1 + Alpha * Del_w1(Input1, Input2, Desired, w0, w1, w2) ,\
        w2 + Alpha * Del_w2(Input1, Input2, Desired, w0, w1, w2)
        w0_list.append(w0)
        w1_list.append(w1)
        w2_list.append(w2)
        loss_list.append(Loss(Input1, Input2, Desired, w0, w1, w2))
        IterTime = IterTime + 1

        if IterTime > 3:
            if abs(w1_list[IterTime-1]-w1_list[IterTime-2])< err:
                if abs(w2_list[IterTime - 1] - w2_list[IterTime - 2]) < err:
                    break

    return w0 ,w1, w2,w0_list,w1_list,w2_list,loss_list,IterTime

def bool_rate(Input1,Input2,Desired,w0,w1,w2):
    boolnum = len(Input1)
    boolT = 0
    for i in range(boolnum):
        if Desired[i]==0:
            if w0+w1*Input1[i]+w2*Input2[i] < 0:
                boolT += 1
        elif Desired[i] ==1:
            if w0 + w1 * Input1[i] + w2 * Input2[i] >= 0:
                boolT += 1
    return boolT / boolnum

Alpha = 0.1
err = 1e-9
w0 ,w1, w2,w0_list,w1_list,w2_list,loss_list,IterTime =\
    GDM_LC(test_Input1,test_Input2,test_Desired,0,0,0,Alpha,err)

print('测试集样本数量:'+str(len(test_Desired)))
print('训练集样本数量:'+str(len(train_Desired)))
print('迭代次数为:'+str(IterTime))
print('学习参数为:'+str(Alpha))
print('误差不超过:'+str(err))
str_line = '线性分类的直线为'+str(w0)+'+'+str(w1)+'x+'+str(w2)+'y=0'
str_test = '测试集正确率'+str(100*bool_rate(test_Input1,test_Input2,test_Desired,w0,w1,w2))+'%'
str_train = '训练集正确率'+str(100*bool_rate(train_Input1,train_Input2,train_Desired,w0,w1,w2))+'%'
print(str_line)
print(str_test)
print(str_train)
#
X =test_Input1
Y = -w0 /w2 -w1*X/w2

plt.figure('线性分类求解（测试集）')
plt.plot(X,Y,label =str_line)
for i in range(len(test_Desired)):
    if test_Desired[i] == 1:
        plt.scatter(test_Input1[i],test_Input2[i],c = 'r',marker= '+')
    else:
        plt.scatter(test_Input1[i], test_Input2[i], c='b', marker='.')
plt.title('测试集样本')
plt.xlabel('测试集坐标x')
plt.ylabel('测试集坐标y')
plt.show()
